package yagwl.client.widget;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import yagwl.client.widget.internal.ButtonBar;

import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.Widget;

/**
 * Lays out a group of fields in single or multiple columns. Labels and values
 * are vertically aligned. Uses method chaining.
 * <p>
 * <b>CSS styles</b><br>
 * .ya-fieldGroup - section<br>
 * .ya-fieldGroup-column-header - column header<br>
 * .ya-fieldGroup-label-req - label of required field<br>
 * .ya-fieldGroup-label-opt - label of optional field<br>
 */
public class FormFieldGroup extends Section {
  public static final int Horizontal = 1;
  public static final int Vertical = 2;
  private FlexTable contentFT = new FlexTable();
  private List<FormField> fieldList = new ArrayList<FormField>();
  private String labelColumnWidth;
  private String dataColumnWidth;
  private String columnSpacing;
  private int numColumns = 1;
  private int tabFlow = Horizontal;
  private ButtonBar buttonBar;

  public FormFieldGroup() {
    this(null);
  }

  public FormFieldGroup(String header) {
    this(header, false);
  }

  public FormFieldGroup(String header, boolean collapsible) {
    super(header, collapsible);
    style = "ya-fieldGroup";
  }

  /**
   * Renders the widget. This must be called for the widget to be rendered. Must
   * be called after all fields has been added.
   */
  void renderUI() {
    setContent(contentFT);

    if (tabFlow == Horizontal)
      renderHorizontalTabFlow();
    else
      renderVerticalTabFlow();
  }

  private void renderVerticalTabFlow() {
    Iterator<FormField> iter = fieldList.iterator();
    FlexTable innerTbl = new FlexTable();
    contentFT.setWidget(0, 0, innerTbl);
    int row = 0, col = 0;
    while (iter.hasNext()) {
      FormField formField = iter.next();
      if (formField.isColumnHeader()) {
        innerTbl.setText(row, 0, formField.getLabel());
        innerTbl.getFlexCellFormatter().setColSpan(row, 0, 2);
        innerTbl.getCellFormatter().addStyleName(row, 0,
            "ya-fieldGroup-column-header");
        row++;
        continue;
      }
      innerTbl.setText(row, 0, formField.getLabel());
      innerTbl.getCellFormatter().addStyleName(row, 0,
          "ya-fieldGroup-label-" + (formField.isRequired() ? "req" : "opt"));
      // innerTbl.getCellFormatter().setVerticalAlignment(row, 0,
      // HasVerticalAlignment.ALIGN_TOP);
      innerTbl.getCellFormatter().setWidth(row, 0, labelColumnWidth + "px");
      innerTbl.setWidget(row, 1, formField.getDataWidget());
      innerTbl.getCellFormatter().setWidth(row, 1, dataColumnWidth + "px");
      row++;
      if (formField.isLastFieldInColumn()) {
        contentFT.getCellFormatter().setWidth(0, col * 2 + 1,
            columnSpacing + "px");
        col++;
        innerTbl = new FlexTable();
        contentFT.setWidget(0, col * 2, innerTbl);
        row = 0;
      }
    }
    if (buttonBar != null) {
      contentFT.setWidget(1, 0, buttonBar);
      contentFT.getFlexCellFormatter().setColSpan(1, 0, (col + 1) * 2);
    }
  }

  private void renderHorizontalTabFlow() {
    Iterator<FormField> iter = fieldList.iterator();
    int row = 0;
    while (iter.hasNext()) {
      for (int col = 0; col < numColumns && iter.hasNext(); col++) {
        FormField formField = iter.next();
        // goNextColumn not applicable for horizontal tab flow
        if (formField.isLastFieldInColumn())
          continue;
        // render label
        contentFT.setText(row, col * 3, formField.getLabel());
        String sel = "ya-fieldGroup-label-"
            + (formField.isRequired() ? "req" : "opt");
        contentFT.getCellFormatter().addStyleName(row, col * 3, sel);
        contentFT.getCellFormatter().setVerticalAlignment(row, col * 3,
            HasVerticalAlignment.ALIGN_TOP);
        if (labelColumnWidth != null)
          contentFT.getCellFormatter().setWidth(row, col * 3, labelColumnWidth);
        // render widget
        contentFT.setWidget(row, col * 3 + 1, formField.getDataWidget());
        contentFT.getCellFormatter().setVerticalAlignment(row, col * 3 + 1,
            HasVerticalAlignment.ALIGN_TOP);
        if (dataColumnWidth != null)
          contentFT.getCellFormatter().setWidth(row, col * 3 + 1,
              dataColumnWidth);
        if (formField.isSpanColumns()) {
          contentFT.getFlexCellFormatter().setColSpan(row, col * 3 + 1, 4);
          continue;
        }
        if (numColumns > 1)
          contentFT.getCellFormatter().setWidth(row, col * 3 + 2,
              columnSpacing + "px");
      }
      row++;
    }
    if (buttonBar != null) {
      contentFT.setWidget(row, 1, buttonBar);
      contentFT.getFlexCellFormatter().setColSpan(row, 1, numColumns * 3 - 1);
    }
  }

  /**
   * Adds a field
   */
  public void addField(String label, Widget dataWidget) {
    addField(label, dataWidget, true);
  }

  /**
   * Adds a field
   */
  public void addField(String label, Widget dataWidget, boolean required) {
    fieldList.add(new FormField().setLabel(label).setDataWidget(dataWidget)
        .setRequired(required));
  }

  /**
   * Adds a field
   */
  public void addField(String label, InputTextBox dataWidget, boolean required) {
    fieldList.add(new FormField().setLabel(label).setDataWidget(dataWidget)
        .setRequired(required));
  }

  /**
   * Adds a field
   */
  public void addField(String label, InputTextArea dataWidget, boolean required) {
    fieldList.add(new FormField().setLabel(label).setDataWidget(dataWidget)
        .setRequired(required));
  }

  /**
   * Adds a field
   */
  public void addField(FormField formField) {
    fieldList.add(formField);
  }

  public List<FormField> getFieldList() {
    return fieldList;
  }

  void setButtonBar(ButtonBar buttonBar) {
    this.buttonBar = buttonBar;
  }

  String getLabelColumnWidth() {
    return labelColumnWidth;
  }

  /**
   * Sets label width
   */
  public FormFieldGroup setLabelColumnWidth(String width) {
    this.labelColumnWidth = width;
    return this;
  }

  String getDataColumnWidth() {
    return dataColumnWidth;
  }

  /**
   * Sets data widget width
   */
  public FormFieldGroup setDataColumnWidth(String width) {
    this.dataColumnWidth = width;
    return this;
  }

  /**
   * Sets number of columns. Applicable for horizontal tab flow only.
   */
  public FormFieldGroup setNumColumns(int numColumns) {
    this.numColumns = numColumns;
    return this;
  }

  /**
   * Sets column spacing
   */
  public FormFieldGroup setColumnSpacing(String columnSpacing) {
    this.columnSpacing = columnSpacing;
    return this;
  }

  /**
   * Sets tab flow: FormFieldGroup.Horizontal or FormFieldGroup.Vertical
   */
  public FormFieldGroup setTabFlow(int tabFlow) {
    this.tabFlow = tabFlow;
    return this;
  }

}
